
package com.mengmeizi.net;

import com.mengmeizi.util.LogOut;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class NetWorkTool {

    private String surl;

    private Map<String, String> params;

    private Map<String, File> files;

    private Method method;

    private int timeout = 5000;

    private String encoding = "UTF-8";

    private Context context;

    private static final String BOUNDARYA = "naosdnfoasndfio";

    public NetWorkTool(Context context) {
        this.context = context;
    }

    public void setURL(String url) {
        surl = url;
    }

    public void setParams(Map<String, String> paramMap) {

        this.params = paramMap;
    }

    public void addParam(String name, String value) {
        if (params == null) {
            this.params = new HashMap<String, String>();
        }
        this.params.put(name, value);
    }

    public void setFiles(Map<String, File> fileMap) {
        this.files = fileMap;
    }

    public void addFile(String name, File file) {
        if (file == null) {
            this.files = new HashMap<String, File>();
        }
        this.files.put(name, file);
    }

    public void removeParam(String name) {
        params.remove(name);
    }

    public void removeFile(String name) {
        files.remove(name);
    }

    public void clearAll() {
        params.clear();
        files.clear();
    }

    public void clearParams() {
        params.clear();
    }

    public void clearFiles() {
        files.clear();
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    /**
     * 将map的键值用 & 和 = 连接起来，用于简单post请求
     * 
     * @param params
     * @return
     */
    private String joinParams(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();
        if (params != null && !params.isEmpty()) {
            Set<Entry<String, String>> enties = params.entrySet();
            Iterator<Entry<String, String>> its = enties.iterator();
            while (its.hasNext()) {
                Entry<String, String> entry = its.next();
                sb.append(entry.getKey());
                sb.append("=");
                sb.append(entry.getValue());
                sb.append("&");
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    /**
     * 将所有参数全部附加到surl，用于get请求
     */
    private void addParamsToURL() {
        String params = joinParams(this.params);
        if (params.length() > 0) {
            surl += "?" + params;
        }
    }

    /**
     * 例：contentType=text/html;charset=utf-8<br/>
     * return utf-8
     * 
     * @param contentType
     * @return
     */
    final static String getEncoding(String contentType) {
        String encoding = null;
        if (contentType != null) {
            if (contentType.contains("charset=")) {
                int index = contentType.indexOf("charset=");
                encoding = contentType.substring(index + 8);
            }
        }
        return encoding;
    }

    public HttpResponse execute(HttpURLConnection conn) throws IOException {
        HttpResponse response = null;
        conn.setConnectTimeout(timeout);
        if (method == Method.GET) {
            // conn.setUseCaches(true);
            InputStream inputStream = conn.getInputStream();
            // String contentType = conn.getContentType();
            // String encoding = getEncoding(contentType);
            // int code = conn.getResponseCode();
            // String status = conn.getResponseMessage();
            // response = new HttpResponse(code, status, encoding, inputStream);
            response = new HttpResponse(-1, null, null, inputStream);
        } else {
            conn.setRequestProperty("Charset", "UTF-8");
            conn.setDoInput(true);
            conn.setDoOutput(true);
            OutputStream os = null;
            if (files == null || files.isEmpty()) {
                os = conn.getOutputStream();
                os.write(joinParams(params).getBytes(encoding));
                LogOut.out(context, "post params[" + joinParams(params) + "]");
            } else {
                conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARYA);
                os = conn.getOutputStream();
                String encodedParams = encodePostBody(params);
                LogOut.out(context, "params[" + encodedParams + "]");
                os.write(encodedParams.getBytes());
                for (String name : files.keySet()) {
                    File file = files.get(name);
                    os.write(encodePostFile(name, file));
                }
                os.write("--".getBytes());
                os.write(BOUNDARYA.getBytes());
                os.write("--".getBytes());
            }
            os.flush();
            os.close();
            response = new HttpResponse(conn);
        }
        return response;
    }

    private String encodePostBody(Map<String, String> params) {
        if (params == null)
            return "";
        StringBuilder sb = new StringBuilder();
        for (String key : params.keySet()) {
            sb.append("--" + BOUNDARYA).append("\r\n");
            sb.append("Content-Disposition: form-data; name=\"" + key + "\"\r\n\r\n" + params.get(key));
            sb.append("\r\n");
        }
        return sb.toString();
    }

    private byte[] encodePostFile(String name, File file) throws IOException {
        LogOut.out(context, "开始写文件：" + name + "," + file.getAbsolutePath());
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        StringBuilder sb = new StringBuilder();
        sb.append("--" + BOUNDARYA + "\r\n");
        sb.append("Content-Disposition: form-data;name=\"" + name + "\";");
        sb.append(" filename=\"" + file.getName() + "\"\r\n");
        sb.append("Content-Type:").append(UploadFileUtiles.getFileContentType(file));
        sb.append("\r\n\r\n");
        LogOut.out(context, sb.toString());
        out.write(sb.toString().getBytes("UTF-8"));
        sb.setLength(0);
        out.write(UploadFileUtiles.getBytes(file));
        out.write("\r\n".getBytes());
        return out.toByteArray();
    }

    /**
     * 将指定的HTTP链接内容存储到指定的的文件中。<br/>
     * 返回值仅当参考。<br/>
     * 
     * @param conn
     * @param filePath 指定存储的文件路径。
     */
    public static boolean download2File(HttpURLConnection conn, String filePath) {
        boolean result = true;
        File file = new File(filePath);
        FileOutputStream fos = null;
        byte[] data = new byte[1024];
        int readLength = -1;
        InputStream is = null;
        try {
            fos = new FileOutputStream(file);
            is = conn.getInputStream();
            while ((readLength = is.read(data)) != -1) {
                fos.write(data, 0, readLength);
                fos.flush();
            }
            fos.flush();
        } catch (IOException ie) {
            result = false;
            ie.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException ie) {
                ie.printStackTrace();
            }
        }
        return result;
    }

    public HttpURLConnection httpConnection() {
        URL url = null;
        HttpURLConnection conn = null;
        try {
            if (method == Method.GET) {
                addParamsToURL();
            }
            LogOut.out(context, "url[" + surl + "]");
            url = new URL(surl);
            conn = (HttpURLConnection) url.openConnection();
            // 需要android.permission.ACCESS_NETWORK_STATE
            // 在没有网络的情况下，返回值为null。
            NetworkInfo networkInfo = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE))
                    .getActiveNetworkInfo();
            if (networkInfo != null) {
                // 如果使用的是运营商网络
                if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                    // 获取默认代理主机ip
                    String host = android.net.Proxy.getDefaultHost();
                    // 获取端口
                    int port = android.net.Proxy.getDefaultPort();
                    if (host != null && port != -1) { // 使用代理
                        // 封装代理連接主机IP与端口号。
                        InetSocketAddress inetAddress = new InetSocketAddress(host, port);
                        // 根据URL链接获取代理类型，本链接适用于TYPE.HTTP
                        java.net.Proxy.Type proxyType = java.net.Proxy.Type.valueOf(url.getProtocol().toUpperCase());
                        java.net.Proxy javaProxy = new java.net.Proxy(proxyType, inetAddress);
                        conn = (HttpURLConnection) url.openConnection(javaProxy);
                    } else { // 不使用代理
                        conn = (HttpURLConnection) url.openConnection();
                    }
                } else { // 如果使用的是wifi网络
                    conn = (HttpURLConnection) url.openConnection();
                }
            } else { // 没网络
                conn = null;
            }
        } catch (NullPointerException npe) {
            npe.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return conn;
    }
}
